package frame

import (
	"fmt"
	"gitee.com/jamon/espoir_go/common/utils"
	"gitee.com/jamon/espoir_go/global"
	"gitee.com/jamon/espoir_go/logger"
	"sync"
	"time"
)

type Manager struct {
	serverInfo utils.Map[string, *Server]
	frameNo    uint32

	config *global.Config
}

var (
	frameMgr  *Manager
	frameOnce sync.Once
)

func GetFrameManager() *Manager {
	frameOnce.Do(func() {
		frameMgr = &Manager{
			serverInfo: utils.NewMap[string, *Server](),
			frameNo:    0,
			config:     global.GetNodeData().Config,
		}
	})
	return frameMgr
}

func (mgr *Manager) Run() {
	curTime := uint64(time.Now().UnixMilli())
	frameInterval := uint64(mgr.config.Frame.GetFrameInterval())
	curFrameNo := curTime / frameInterval
	curFrameTime := curFrameNo * frameInterval

	for {
		mgr.serverInfo.LockRange(func(key string, value *Server) {
			if value.Status == 1 {
				value.Sync()
			}
			return
		})

		curTime := uint64(time.Now().UnixMilli())
		nextFrameTime := curFrameTime + frameInterval
		needWaitTime := nextFrameTime - curTime
		if needWaitTime < 0 {
			needWaitTime = 0
		}

		time.Sleep(time.Duration(needWaitTime) * time.Millisecond)

		curFrameNo++
		curFrameTime = nextFrameTime
	}
}

func (mgr *Manager) CreateServer(gameID string, userList []*User) (server *Server, err error) {
	if _, exist := mgr.serverInfo.Get(gameID); exist {
		err = fmt.Errorf("server already exists, gameID: %s", gameID)
		return
	}

	server = NewServer(gameID)
	server.AddUsers(userList)
	mgr.serverInfo.Put(gameID, server)
	server.userIDs = make([]uint64, len(userList))
	logger.Info("Success: ", logger.Kwargs{"gameID": gameID, "userList": userList})
	return
}

func (mgr *Manager) DeleteServer(gameID string) {
	server, exist := mgr.serverInfo.Get(gameID)
	if !exist {
		logger.Warn("server not exist", logger.Kwargs{"gameID": gameID})
		return
	}
	server.Stop()
	mgr.serverInfo.Remove(gameID)
	logger.Info("Success: ", logger.Kwargs{"gameID": gameID})
	return
}

func (mgr *Manager) AddOp(userID uint64, gameID string, jsonOp string) (err error) {
	server, exist := mgr.serverInfo.Get(gameID)
	if !exist {
		err = fmt.Errorf("server not found, gameID: %s", gameID)
		return
	}
	server.AddOp(userID, jsonOp)
	return
}

func (mgr *Manager) Close() {
	//TODO
}
